﻿using Leeder.Logger;
using SPSAndong.Business;
using SPSAndong.Comm;
using SPSAndong.Model;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SPSAndong.Handle
{
    /// <summary>
    /// 语音播报器监听服务
    /// </summary>
    public class VoiceHelper
    {
        /// <summary>
        /// 日志
        /// </summary>
        LogOperate LogObj => Log.GetLogger(this.GetType());
        MusicSetBLL musicSetBLL = new MusicSetBLL();
        /// <summary>
        /// 所有区域音乐配置
        /// </summary>
        public ConcurrentDictionary<int, List<VoiceAreaMusicModel>> voiceMusic = new ConcurrentDictionary<int, List<VoiceAreaMusicModel>>();
        /// <summary>
        /// 按时长播放，关闭音乐以最后呼叫指令为主
        /// </summary>
        public ConcurrentDictionary<int, DateTime?> playTimesExit = new ConcurrentDictionary<int, DateTime?>();
        /// <summary>
        /// 实时消息显示队列
        /// </summary>
        public ConcurrentQueue<string> RealMsg = new ConcurrentQueue<string>();
        /// <summary>
        /// 服务端监听socket
        /// </summary>
        private Socket socketWatch;
        /// <summary>
        /// 语音播报控制队列,对每个语音播盒各加一把锁
        /// </summary>
        private ConcurrentDictionary<string, int> _controlQueue = new ConcurrentDictionary<string, int>();


        /// <summary>
        /// 在线的套接字连接,将远程连接的客户端的(ip地址+端口号)和socket存入集合
        /// </summary>
        public ConcurrentDictionary<string, SocClient> disSocClient = new ConcurrentDictionary<string, SocClient>();


        /// <summary>
        /// 启动服务端
        /// </summary>
        public void InitSocket()
        {
            InitAreaTypePlayExitDateTime();
            //从数据库加载语音信息
            GetMusicBroadcastSet();

            Task.Run(async delegate
            {
                foreach (var item in GolbalVariable.VoiceAreaMusicList)
                {
                    try
                    {
                        SocClient socClient = new SocClient(IPAddress.Parse(item.IPAddress), 23);
                        if (socClient.Connect())
                        {
                            LogObj.Info(item.IPAddress + "连接成功");
                            if (!disSocClient.ContainsKey(item.IPAddress))
                                disSocClient.TryAdd(item.IPAddress, socClient);
                        }
                        else
                        {
                            LogObj.Error(item.IPAddress + "连接服务端失败");
                        }
                    }catch(Exception ex)
                    {

                    }

                }
            });
        }
        /// <summary>
        /// 初始化音乐关闭最迟时间
        /// </summary>
        private void InitAreaTypePlayExitDateTime()
        {
            for (int i = 1; i <= 4; i++)
                playTimesExit.TryAdd(i, DateTime.Now);
        }
        /// <summary>
        /// 获取数据库语音播报信息
        /// </summary>
        public void GetMusicBroadcastSet()
        {
            try
            {
                voiceMusic.Clear();
                if (GolbalVariable.VoiceAreaMusicList != null && GolbalVariable.VoiceAreaMusicList.Count > 0)
                {
                    foreach (var item in GolbalVariable.VoiceAreaMusicList)
                    {
                        if (voiceMusic.ContainsKey(item.AreaType))
                            voiceMusic[item.AreaType].Add(item);
                        else
                        {
                            List<VoiceAreaMusicModel> music = new List<VoiceAreaMusicModel>() { item };
                            voiceMusic.TryAdd(item.AreaType, music);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogObj.Error(ex.Message);
            }
        }

        /// <summary>
        /// 解锁
        /// </summary>
        private void ClearControlQueue(string ipAddress)
        {
            if (_controlQueue.ContainsKey(ipAddress))
            {
                int key;
                _controlQueue.TryRemove(ipAddress, out key);
            }
        }
        /// <summary>
        /// 服务器不停的接收客户端发来的消息,监控客户端是否离线
        /// </summary>
        /// <param name="o"></param>
        private async void Receive(VoiceComControlModel cmd)
        {
            try
            {
                if (disSocClient.ContainsKey(cmd.IPAdress))
                {
                    //客户端连接成功后  服务器接收客户端发送的消息
                    byte[] buffer = new byte[1024];
                    //实际接收到的有效字节数
                    string r = disSocClient[cmd.IPAdress].ReceiveData();
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
                CloseSocket(cmd);
            }
            ClearControlQueue(cmd.IPAdress);
            await Task.Delay(1);
        }
        /// <summary>
        /// 关闭Socket
        /// </summary>
        /// <param name="cmd"></param>
        private void CloseSocket(VoiceComControlModel cmd)
        {
            if (disSocClient.ContainsKey(cmd.IPAdress))
            {
                SocClient socket;
                disSocClient.TryRemove(cmd.IPAdress, out socket);
                socket.DisConnect();
            }
        }

        /// <summary>
        /// 播放计时，时间到音乐停止
        /// </summary>
        public async void TickVoiceMusicNew(int paytimes, int areaType, string ip, SocClient client)
        {
            //延迟时间
            await Task.Delay((paytimes) * 1000);
            var ms = voiceMusic[areaType].FirstOrDefault(x => x.IPAddress == ip);
            //如果音乐已手动关闭则无需再发送关闭指令
            if (ms.IsPlaying)
            {
                if (playTimesExit[areaType] <= DateTime.Now)
                {
                    voiceMusic[areaType].FirstOrDefault(x => x.IPAddress == ip).IsPlaying = false;
                    //将结束音乐播放命令写入队列
                    var res = VoiceCom.Stop();
                    client.SendData(res);
                }
            }
        }

        /// <summary>
        /// 设置音量
        /// </summary>
        /// <param name="areaType"></param>
        /// <param name="start"></param>
        /// <param name="ipAdd"></param>
        /// <param name="times"></param>
        public async void ExecControlVoiceVolumeCommand(int areaType, bool isAdd, string ipAdd = "")
        {
            if (!voiceMusic.ContainsKey(areaType))
            {
                LogObj.Error(areaType + ":该区域未配置语音设备");
                return;
            }
            //通过区域类型找到对应的语音播放信息
            List<VoiceAreaMusicModel> broadcast = voiceMusic[areaType];
            if (broadcast != null && broadcast.Count > 0 && !string.IsNullOrEmpty(ipAdd))
                broadcast = broadcast.Where(x => x.IPAddress == ipAdd).ToList();
            //通过区域音乐设置来执行相关的命令
            foreach (var ip in broadcast)
            {
                if (!disSocClient.ContainsKey(ip.IPAddress))
                {
                    LogObj.Error(ip.IPAddress + ":该语音设备未上线");
                    continue;
                }
                byte[] res = null;
                if (isAdd)
                    res = VoiceCom.VoiceAdd();   //增大播放音量
                else
                    res = VoiceCom.VoiceReduce(); //减小播放音量
                if (res != null)
                {
                    //voiceMusic[areaType] = broadcast;
                    disSocClient[ip.IPAddress].SendData(res);
                }
            }
            await Task.Delay(1);
        }

        /// <summary>
        /// 执行语音命令
        /// </summary>
        /// <param name="areaType"></param>
        /// <param name="start"></param>
        /// <param name="ip"></param>
        /// <param name="times"></param>
        public async void ExecVoiceCommand(int areaType, bool start, string ipAdd = "", int times = 0)
        {
            if (!voiceMusic.ContainsKey(areaType))
            {
                LogObj.Error(areaType + ":该区域未配置语音设备");
                return;
            }
            //通过区域类型找到对应的语音播放信息
            List<VoiceAreaMusicModel> broadcast = voiceMusic[areaType];
            //通过区域音乐设置来执行相关的命令
            foreach (var ip in broadcast)
            {
                LogObj.Info($"发送语音指令：{ip.IPAddress}");
                if (!string.IsNullOrEmpty(ipAdd))
                {
                    if (ipAdd != ip.IPAddress)
                        continue;
                }
                if (!disSocClient.ContainsKey(ip.IPAddress))
                {
                    LogObj.Error(ip.IPAddress + ":该语音设备未上线");
                    continue;
                }
                if (!ip.MusicState)
                {
                    LogObj.Error(ip.IPAddress + ":该区域音乐未启用");
                    continue;
                }
                if (!ip.BroadcastState)
                {
                    LogObj.Error(ip.IPAddress + ":该广播未启用");
                    continue;
                }
                if (ip.MusicId <= 0)
                {
                    LogObj.Error(ip.IPAddress + ":该区域音乐未配置");
                    continue;
                }
                byte[] res = null;
                if (ip.IsPlayAlong)
                {
                    //音乐循环播放
                    if (start)
                    {
                        if (ip.IsPlaying)
                            continue;
                        ip.IsPlaying = true;
                        res = VoiceCom.PlayLoop(ip.MusicId);
                        disSocClient[ip.IPAddress].SendData(res);
                    }
                    else
                    {
                        ip.IsPlaying = false;
                        res = VoiceCom.StopLoop();
                        disSocClient[ip.IPAddress].SendData(res);
                        Thread.Sleep(50);
                        res = VoiceCom.Stop();
                        disSocClient[ip.IPAddress].SendData(res);
                        voiceMusic[areaType] = broadcast;
                        continue;
                    }

                }
                else if (ip.PlayTimes > 0)
                {
                    if (start)
                    {
                        ip.IsPlaying = true;
                        //设置音乐结束时间，-1：一秒的延迟
                        playTimesExit[areaType] = DateTime.Now.AddSeconds(ip.PlayTimes - 1);
                        res = VoiceCom.Play(ip.MusicId);
                        disSocClient[ip.IPAddress].SendData(res);
                        await Task.Run(() => { TickVoiceMusicNew(ip.PlayTimes, areaType, ip.IPAddress, disSocClient[ip.IPAddress]); });
                    }
                    else
                    {
                        if (ip.IsPlaying)
                        {
                            //设置的播放时间未到，手动按下关闭按钮
                            ip.IsPlaying = false;
                            res = VoiceCom.Stop();
                            disSocClient[ip.IPAddress].SendData(res);
                        }
                    }
                }
                //if (res != null)
                //    disSocClient[ip.IPAddress].SendData(res);
            }
            //voiceMusic[areaType] = broadcast;
        }

        /// <summary>
        /// 关闭所有语音
        /// </summary>
        public void CloseAllVoice()
        {
            foreach (KeyValuePair<int, List<VoiceAreaMusicModel>> item in voiceMusic)
            {
                foreach (var v in item.Value)
                {
                    if (!disSocClient.ContainsKey(v.IPAddress))
                        continue;
                    if (!v.IsPlaying)
                        continue;
                    byte[] res = null;
                    if (v.IsPlayAlong)
                    {
                        res = VoiceCom.StopLoop();
                        disSocClient[v.IPAddress].SendData(res);
                        Thread.Sleep(50);
                        res = VoiceCom.Stop();
                        disSocClient[v.IPAddress].SendData(res);
                    }
                    else
                    {
                        res = VoiceCom.Stop();
                        disSocClient[v.IPAddress].SendData(res);
                    }
                }
            }
        }
        /// <summary>
        /// 关闭语音服务
        /// </summary>
        public void StopVoiceServer()
        {
            //关闭监听服务端套接字
            if (socketWatch != null)
            {
                socketWatch.Close();
                foreach (KeyValuePair<string, SocClient> x in disSocClient)
                {
                    x.Value.DisConnect();
                    SocClient t;
                    disSocClient.TryRemove(x.Key, out t);
                }
            }
            socketWatch = null;
        }
    }
}
